<?php

namespace app\common\service;

use app\common\dao\payment\PaymentConfigDao;
use app\common\model\BillingRecords;
use app\common\model\MembershipOrders;
use support\Log;

/**
 * 易支付服务类
 * Class YiPayService
 * @package app\common\service
 */
class YiPayService
{
    private $config;
    private $apiUrl;
    private $merchantId;
    private $merchantKey;
    private $notifyUrl;
    private $returnUrl;

    public function __construct()
    {
        $this->loadConfig();
    }

    /**
     * 加载支付配置
     */
    private function loadConfig()
    {
        $configDao = new PaymentConfigDao();
        $configs = $configDao->getActiveConfigs('yipay');
        
        foreach ($configs as $config) {
            switch ($config['config_key']) {
                case 'api_url':
                    $this->apiUrl = rtrim($config['config_value'], '/');
                    break;
                case 'merchant_id':
                    $this->merchantId = $config['config_value'];
                    break;
                case 'merchant_key':
                    $this->merchantKey = $config['config_value'];
                    break;
                case 'notify_url':
                    $this->notifyUrl = $config['config_value'];
                    break;
                case 'return_url':
                    $this->returnUrl = $config['config_value'];
                    break;
            }
        }
    }

    /**
     * 创建支付订单
     * @param int $userId 用户ID
     * @param string $orderType 订单类型: membership, balance
     * @param float $amount 金额
     * @param string $description 商品描述
     * @param array $extraData 额外数据
     * @return array 支付参数
     */
    public function createOrder($userId, $orderType, $amount, $description, $extraData = [])
    {
        try {
            // 生成订单号
            $orderNo = $this->generateOrderNo($userId);
            
            // 创建订单记录
            $orderData = [
                'user_id' => $userId,
                'order_no' => $orderNo,
                'amount' => $amount,
                'description' => $description,
                'order_type' => $orderType,
                'extra_data' => json_encode($extraData),
                'payment_method' => 'yipay',
                'payment_status' => 'pending',
                'created_at' => date('Y-m-d H:i:s')
            ];

            // 根据订单类型创建不同的订单
            if ($orderType === 'membership') {
                $order = new MembershipOrders();
                $orderData['plan_type'] = $extraData['plan_type'] ?? 'premium';
                $orderData['months'] = $extraData['months'] ?? 1;
                $orderData['final_amount'] = $amount;
            } else {
                // 余额充值订单
                $order = new \app\common\model\BalanceOrders();
            }

            $order->save($orderData);

            // 构建支付参数
            $payParams = [
                'pid' => $this->merchantId,
                'type' => 'alipay', // 默认使用支付宝，可根据需要调整
                'out_trade_no' => $orderNo,
                'notify_url' => $this->notifyUrl,
                'return_url' => $this->returnUrl,
                'name' => $description,
                'money' => $amount,
                'sitename' => 'XappTool'
            ];

            // 生成签名
            $payParams['sign'] = $this->generateSign($payParams);
            $payParams['sign_type'] = 'MD5';

            return [
                'success' => true,
                'order_no' => $orderNo,
                'payment_url' => $this->buildPaymentUrl($payParams),
                'params' => $payParams
            ];

        } catch (\Exception $e) {
            Log::error('创建支付订单失败: ' . $e->getMessage(), [
                'user_id' => $userId,
                'order_type' => $orderType,
                'amount' => $amount
            ]);
            
            return [
                'success' => false,
                'message' => '创建支付订单失败: ' . $e->getMessage()
            ];
        }
    }

    /**
     * 处理支付回调
     * @param array $notifyData 回调数据
     * @return array 处理结果
     */
    public function handleNotify($notifyData)
    {
        try {
            // 验证签名
            if (!$this->verifySign($notifyData)) {
                return ['success' => false, 'message' => '签名验证失败'];
            }

            // 获取订单信息
            $orderNo = $notifyData['out_trade_no'];
            $tradeNo = $notifyData['trade_no'] ?? '';
            $money = $notifyData['money'] ?? 0;
            $status = $notifyData['trade_status'] ?? '';

            // 查找订单
            $order = MembershipOrders::where('order_no', $orderNo)->first();
            if (!$order) {
                return ['success' => false, 'message' => '订单不存在'];
            }

            // 检查订单状态
            if ($order['payment_status'] === 'completed') {
                return ['success' => true, 'message' => '订单已处理'];
            }

            // 验证金额
            if (floatval($money) != floatval($order['final_amount'])) {
                Log::warning('支付金额不匹配', [
                    'order_no' => $orderNo,
                    'notify_money' => $money,
                    'order_amount' => $order['final_amount']
                ]);
            }

            // 处理支付成功
            if ($status === 'TRADE_SUCCESS' || $status === 'TRADE_FINISHED') {
                $this->processPaymentSuccess($order, $tradeNo, $notifyData);
            } else {
                // 更新订单状态为失败
                $order->save([
                    'payment_status' => 'failed',
                    'updated_at' => date('Y-m-d H:i:s')
                ]);
            }

            return ['success' => true, 'message' => '处理成功'];

        } catch (\Exception $e) {
            Log::error('支付回调处理失败: ' . $e->getMessage(), [
                'notify_data' => $notifyData
            ]);
            
            return ['success' => false, 'message' => '处理失败: ' . $e->getMessage()];
        }
    }

    /**
     * 处理支付成功
     * @param MembershipOrders $order 订单对象
     * @param string $tradeNo 第三方交易号
     * @param array $notifyData 回调数据
     */
    private function processPaymentSuccess($order, $tradeNo, $notifyData)
    {
        // 更新订单状态
        $order->save([
            'payment_status' => 'completed',
            'transaction_id' => $tradeNo,
            'updated_at' => date('Y-m-d H:i:s')
        ]);

        // 更新用户会员信息
        $this->activateMembership($order);

        // 记录账单
        $this->recordBilling($order, 'membership_purchase', $order['final_amount']);

        Log::info('会员购买成功', [
            'user_id' => $order['user_id'],
            'order_no' => $order['order_no'],
            'plan_type' => $order['plan_type'],
            'amount' => $order['final_amount']
        ]);
    }

    /**
     * 激活用户会员
     * @param MembershipOrders $order 订单对象
     */
    private function activateMembership($order)
    {
        $userId = $order['user_id'];
        $planType = $order['plan_type'];
        $months = $order['months'];

        // 计算会员有效期
        $startDate = date('Y-m-d');
        $endDate = date('Y-m-d', strtotime("+{$months} months"));

        // 检查是否已有有效会员
        $existingMembership = \app\common\model\UserMemberships::where('user_id', $userId)
            ->where('status', 'active')
            ->where('end_date', '>=', date('Y-m-d'))
            ->first();

        if ($existingMembership) {
            // 延长现有会员
            $newEndDate = date('Y-m-d', strtotime($existingMembership['end_date'] . " +{$months} months"));
            $existingMembership->save([
                'end_date' => $newEndDate,
                'updated_at' => date('Y-m-d H:i:s')
            ]);
        } else {
            // 创建新会员
            $membership = new \app\common\model\UserMemberships();
            $membership->save([
                'user_id' => $userId,
                'plan_type' => $planType,
                'status' => 'active',
                'start_date' => $startDate,
                'end_date' => $endDate,
                'auto_renew' => $order['auto_renew'] ?? 1,
                'created_at' => date('Y-m-d H:i:s')
            ]);
        }
    }

    /**
     * 记录账单
     * @param array $order 订单数据
     * @param string $billType 账单类型
     * @param float $amount 金额
     */
    private function recordBilling($order, $billType, $amount)
    {
        $billing = new BillingRecords();
        $billing->save([
            'user_id' => $order['user_id'],
            'bill_type' => 'consumption',
            'bill_subtype' => $billType,
            'amount' => $amount,
            'balance_before' => 0,
            'balance_after' => 0,
            'related_id' => $order['id'],
            'description' => "购买{$order['plan_type']}会员 - {$order['months']}个月",
            'payment_method' => 'yipay',
            'transaction_id' => $order['transaction_id'],
            'status' => 'completed',
            'created_at' => date('Y-m-d H:i:s')
        ]);
    }

    /**
     * 生成订单号
     * @param int $userId 用户ID
     * @return string 订单号
     */
    private function generateOrderNo($userId)
    {
        return date('YmdHis') . str_pad($userId, 6, '0', STR_PAD_LEFT) . mt_rand(1000, 9999);
    }

    /**
     * 生成签名
     * @param array $params 参数数组
     * @return string 签名
     */
    private function generateSign($params)
    {
        // 按参数名排序
        ksort($params);
        
        // 拼接字符串
        $signStr = '';
        foreach ($params as $key => $value) {
            if ($key !== 'sign' && $key !== 'sign_type' && $value !== '') {
                $signStr .= $key . '=' . $value . '&';
            }
        }
        
        // 添加密钥
        $signStr = rtrim($signStr, '&') . $this->merchantKey;
        
        // 生成MD5签名
        return md5($signStr);
    }

    /**
     * 验证签名
     * @param array $params 参数数组
     * @return bool 验证结果
     */
    private function verifySign($params)
    {
        if (!isset($params['sign'])) {
            return false;
        }
        
        $sign = $params['sign'];
        $calculatedSign = $this->generateSign($params);
        
        return $sign === $calculatedSign;
    }

    /**
     * 构建支付URL
     * @param array $params 支付参数
     * @return string 支付URL
     */
    private function buildPaymentUrl($params)
    {
        $queryString = http_build_query($params);
        return $this->apiUrl . '/submit.php?' . $queryString;
    }

    /**
     * 查询订单状态
     * @param string $orderNo 订单号
     * @return array 查询结果
     */
    public function queryOrder($orderNo)
    {
        try {
            $params = [
                'act' => 'order',
                'pid' => $this->merchantId,
                'key' => $this->merchantKey,
                'out_trade_no' => $orderNo
            ];

            $queryUrl = $this->apiUrl . '/api.php?' . http_build_query($params);
            
            // 发起查询请求
            $response = $this->httpGet($queryUrl);
            $result = json_decode($response, true);

            if (isset($result['status']) && $result['status'] === 'success') {
                return [
                    'success' => true,
                    'data' => $result['data'] ?? []
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $result['msg'] ?? '查询失败'
                ];
            }

        } catch (\Exception $e) {
            Log::error('订单查询失败: ' . $e->getMessage(), [
                'order_no' => $orderNo
            ]);
            
            return [
                'success' => false,
                'message' => '查询失败: ' . $e->getMessage()
            ];
        }
    }

    /**
     * HTTP GET请求
     * @param string $url 请求URL
     * @return string 响应内容
     */
    private function httpGet($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($error) {
            throw new \Exception('CURL Error: ' . $error);
        }

        if ($httpCode !== 200) {
            throw new \Exception('HTTP Error: ' . $httpCode);
        }

        return $response;
    }
}